{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Function Arguments and  Mutability"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consider a function that receives a *string* argument, and changes the argument in some way:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def process(s):\n",
    "    print('initial s # = {0}'.format(hex(id(s))))\n",
    "    s = s + ' world'\n",
    "    print('s after change # = {0}'.format(hex(id(s))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "my_var # = 0x1e7e96fc420\n"
     ]
    }
   ],
   "source": [
    "my_var = 'hello'\n",
    "print('my_var # = {0}'.format(hex(id(my_var))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that when *s* is received, it is referencing the same object as *my_var*.\n",
    "\n",
    "After we \"modify\" *s*, *s* is pointing to a new memory address:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial s # = 0x1e7e96fc420\n",
      "s after change # = 0x1e7e97153b0\n"
     ]
    }
   ],
   "source": [
    "process(my_var)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And our own variable *my_var* is still pointing to the original memory address:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "my_var # = 0x1e7e96fc420\n"
     ]
    }
   ],
   "source": [
    "print('my_var # = {0}'.format(hex(id(my_var))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see how this works with mutable objects:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def modify_list(items):\n",
    "    print('initial items # = {0}'.format(hex(id(items))))\n",
    "    if len(items) > 0:\n",
    "        items[0] = items[0] ** 2\n",
    "    items.pop()\n",
    "    items.append(5)\n",
    "    print('final items # = {0}'.format(hex(id(items))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "my_list # = 0x1e7e972d308\n"
     ]
    }
   ],
   "source": [
    "my_list = [2, 3, 4]\n",
    "print('my_list # = {0}'.format(hex(id(my_list))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial items # = 0x1e7e972d308\n",
      "final items # = 0x1e7e972d308\n"
     ]
    }
   ],
   "source": [
    "modify_list(my_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4, 3, 5]\n",
      "my_list # = 0x1e7e972d308\n"
     ]
    }
   ],
   "source": [
    "print(my_list)\n",
    "print('my_list # = {0}'.format(hex(id(my_list))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, throughout all the code, the memory address referenced by *my_list* and *items* is always the **same** (shared) reference - we are simply modifying the contents (**internal state**) of the object at that memory address."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, even with immutable container objects we have to be careful, e.g. a tuple containing a list (the tuple is immutable, but the list element inside the tuple **is** mutable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def modify_tuple(t):\n",
    "    print('initial t # = {0}'.format(hex(id(t))))\n",
    "    t[0].append(100)\n",
    "    print('final t # = {0}'.format(hex(id(t))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "my_tuple = ([1, 2], 'a')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0x1e7e9614288'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hex(id(my_tuple))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial t # = 0x1e7e9614288\n",
      "final t # = 0x1e7e9614288\n"
     ]
    }
   ],
   "source": [
    "modify_tuple(my_tuple)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([1, 2, 100], 'a')"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_tuple"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, the first element of the tuple was mutated."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
